package mil.af.amc.adpetracker.service;

import mil.af.amc.adpetracker.dao.AdpeAccountDao;
import mil.af.amc.adpetracker.dao.DrmoPackageDao;
import mil.af.amc.adpetracker.dao.EquipmentItemDao;
import mil.af.amc.adpetracker.dao.MaintenanceEntryDao;
import mil.af.amc.adpetracker.model.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.mail.MailSender;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Implementation for DrmoPackage service
 *
 * @author TSgt Jason Ferguson
 */

@Service("drmoPackageService")
public class DrmoPackageServiceImpl implements DrmoPackageService {

    private static final Log log = LogFactory.getLog(DrmoPackageServiceImpl.class);

    private AdpeAccountDao adpeAccountDao;

    @Autowired
    public void setAdpeAccountDao(AdpeAccountDao adpeAccountDao) {
        this.adpeAccountDao = adpeAccountDao;
    }

    private DrmoPackageDao drmoPackageDao;

    @Autowired
    public void setDrmoPackageDao(DrmoPackageDao drmoPackageDao) {
        this.drmoPackageDao = drmoPackageDao;
    }

    private EquipmentItemDao equipmentItemDao;

    @Autowired
    public void setEquipmentItemDao(EquipmentItemDao equipmentItemDao) {
        this.equipmentItemDao = equipmentItemDao;
    }

    private MailSender mailSender;

    @Autowired
    public void setMailSender(MailSender mailSender) {
        this.mailSender = mailSender;
    }

    private EquipmentItemService equipmentItemService;

    @Autowired
    public void setEquipmentItemService(EquipmentItemService equipmentItemService) {
        this.equipmentItemService = equipmentItemService;
    }

    private MaintenanceEntryDao maintenanceEntryDao;

    @Autowired
    public void setMaintenanceEntryDao(MaintenanceEntryDao maintenanceEntryDao) {
        this.maintenanceEntryDao = maintenanceEntryDao;
    }

    // TODO: make sure that the given dtid is unique
    public DrmoPackage createPackage(Map map) throws ServiceException {

        String dtid = (String) map.get("dtid");
        if (drmoPackageDao.getByDtid(dtid) != null) {
            throw new ServiceException("error.dtid.exists", "DTID already exists");
        }

        DrmoPackage pkg = new DrmoPackage();
        pkg.setDtid((String) map.get("dtid"));

        int adpeAccountId = (Integer) map.get("adpeAccount");
        AdpeAccount acct = adpeAccountDao.getById(adpeAccountId);
        pkg.setAdpeAccount(acct);

        pkg.setPackageCreateDate(new Date());

        // Get the Integer itemConditionId, then use it for the array index from the standard Enum values() method
        int itemConditionId = (Integer) map.get("itemConditionId");
        pkg.setCondition(Condition.values()[itemConditionId]);

        String dateFormatPattern = "dd-MMM-yyyy";
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormatPattern);

        String createDate = (String) map.get("turninDate");

        try {
            Date pDate = sdf.parse(createDate);
            pkg.setPackageCreateDate(pDate);
        } catch (ParseException e) {
            log.debug("Bad date input: " + createDate, e);
            System.out.println("Bad date input: " + createDate);
        }
//        try {
//            Date turninDate = new SimpleDateFormat("d-MM-yyyy").parse(strDate);
//            System.out.println(turninDate);
//        } catch (ParseException e) {
//
//        }
        //ItemCondition cond = itemConditionDao.getById(itemConditionId);
        //pkg.setItemCondition(cond);

        drmoPackageDao.saveOrUpdate(pkg);

        // Get the package again, fully populated
        pkg = drmoPackageDao.getByDtid(dtid);

        Integer[] packageItemId = (Integer[]) map.get("pkgItemId");
        for (Integer p : packageItemId) {
            EquipmentItem item = equipmentItemDao.getById(p);
            item.setDrmoPackage(pkg);
            item.setItemStatus(Status.PendingDrmo);

            MaintenanceEntry maint = new MaintenanceEntry();
            maint.setEntryDate(new Date());
            maint.setEntryText("Item added to DRMO Package " + pkg.getDtid());
            maint.setItem(item);

            item.getMaintenanceEntries().add(maint);
            equipmentItemDao.save(item);

            maintenanceEntryDao.save(maint);

            pkg.getIdentifiedItems().add(item);
        }

        drmoPackageDao.saveOrUpdate(pkg);

        return pkg;
    }

    public DrmoPackage editPackage(Map map) throws ServiceException {

        int packageId = (Integer) map.get("packageId");
        DrmoPackage pkg = drmoPackageDao.getById(packageId);

        // This is the critical line that determines when a package is complete or not! If a "completed" status is
        // passed in, the turnin date is set!
        if (pkg.getTurninDate() == null && ((Integer) map.get("statusId")) == 2) {
            pkg.setTurninDate(new Date());
        }

        // Since this is a set, not a list, duplicates get discarded. Yay.
        Integer[] pkgIdArr = (Integer[]) map.get("pkgItemId");
        for (int pkgId : pkgIdArr) {
            EquipmentItem item = equipmentItemDao.getById(pkgId);
            item.setDrmoPackage(pkg);
            equipmentItemDao.save(item);
            pkg.getIdentifiedItems().add(item);
        }
//        List<EquipmentItem> allEquipment = new ArrayList<EquipmentItem>();
//        for (int i=0; i<pkgIdArr.length; i++) {
//            EquipmentItem item = equipmentItemDao.getById(pkgIdArr[i]);
//            allEquipment.add(item);
//        }

        // Add any new items
//        for (Iterator<EquipmentItem> it=allEquipment.iterator(); it.hasNext();) {
//
//            EquipmentItem item = it.next();
//            if (!pkg.getIdentifiedItems().contains(item)) {
//                addItemToPackage(pkg, item);
//                //pkg.getIdentifiedItems().add(item);
//            }
//        }

        // Remove any "bad" items
//        for (Iterator<EquipmentItem> it=pkg.getIdentifiedItems().iterator(); it.hasNext();) {
//
//            EquipmentItem item = it.next();
//            if (!allEquipment.contains(item)) {
//                removeItemFromPackage(pkg, item);
//                //addItemToPackage(pkg, item);
//                //pkg.getIdentifiedItems().remove(item);
//            }
//        }

        return pkg;

    }

//    public void addItemsToPackage(DrmoPackage pkg, Integer[] pkgIds) throws ServiceException {
//
//        DrmoPackage p = drmoPackageDao.getByDtid(pkg.getDtid());
//
//        for (int i = 0; i < pkgIds.length; i++) {
//            EquipmentItem item = equipmentItemDao.getById(pkgIds[i]);
//
//            if (item.getAssignedUser() != null) {
//                try {
//                    equipmentItemService.unassignItem(item);
//                } catch (ServiceException e) {
//                    throw new ServiceException(e);
//                }
//            }
//            if (!p.getIdentifiedItems().contains(item)) {
//                p.getIdentifiedItems().add(item);
//            }
//            item.setDrmoPackage(p);
//            equipmentItemDao.saveOrUpdate(item);
//
//            // have to do this so the maintenance entry doesn't throw an NPE... an evil, evil NPE... I hate them so very much...
//            EquipmentItem editedItem = equipmentItemDao.getBySerialNumber(item.getSerial());
//
//            MaintenanceEntry maint = new MaintenanceEntry();
//            maint.setEntryDate(new Date());
//            maint.setEntryText("Item added to DRMO package " + pkg.getDtid());
//            maint.setItem(editedItem);
//
//            maintenanceEntryDao.saveOrUpdate(maint);
//
//        }
//        drmoPackageDao.saveOrUpdate(p);
//
//        DrmoPackage dpkg = drmoPackageDao.getByDtid(p.getDtid());
//
//
//
//    }

    // TODO: make addItemToPackage protected
    public void addItemToPackage(DrmoPackage pkg, EquipmentItem item) throws ServiceException {

        // Make sure this item is not part of another DRMO package
        // TODO: Throw a ServiceException if the item can't be added to a package?
        if (item.getDrmoPackage() == null) {

            // If item is assigned to a user, unassign it!
            if (item.getAssignedUser() != null) {
                try {
                    equipmentItemService.unassignItem(item.getId());
                } catch (ServiceException e) {
                    throw new ServiceException(e);
                }
            }

            pkg.getIdentifiedItems().add(item);
            //drmoPackageDao.save(pkg);

            item.setDrmoPackage(pkg);
            //equipmentItemDao.save(item);

            // Maintenance Log Entry Here!
            MaintenanceEntry maint = new MaintenanceEntry();
            maint.setEntryDate(new Date());
            maint.setEntryText("Item added to DRMO package " + pkg.getDtid());
            maint.setItem(item);

            maintenanceEntryDao.saveOrUpdate(maint);

            equipmentItemDao.save(item);
            drmoPackageDao.save(pkg);
        }
    }

//    public void removeItemFromPackage(DrmoPackage pkg, EquipmentItem item) {
//
//        pkg.getIdentifiedItems().remove(item);
//
//        MaintenanceEntry maint = new MaintenanceEntry();
//        maint.setEntryDate(new Date());
//        maint.setEntryText("Item removed from DRMO package " + pkg.getDtid());
//        maint.setItem(item);
//
//        maintenanceEntryDao.saveOrUpdate(maint);
//
//    }

    public void deletePackage(int drmoPackageId) throws ServiceException {

        DrmoPackage pkg = drmoPackageDao.getById(drmoPackageId);

        if (pkg.getStatus() == DrmoPackageStatus.CLOSED) {
            throw new ServiceException("error.delete.closed.package", "Package is closed");
        }

        for (EquipmentItem item : pkg.getIdentifiedItems()) {
            item.setDrmoPackage(null);

            MaintenanceEntry maint = new MaintenanceEntry();
            maint.setItem(item);
            maint.setEntryDate(new Date());
            maint.setEntryText("Item removed from package " + pkg.getDtid() + " (package deleted before turnin)");

            maintenanceEntryDao.save(maint);
            equipmentItemDao.save(item);
        }

        drmoPackageDao.delete(pkg);
    }

    public void closePackage(int packageId) {

        DrmoPackage pkg = drmoPackageDao.getById(packageId);
        pkg.setStatus(DrmoPackageStatus.CLOSED);

        pkg.setTurninDate(new Date());

        // Mark the item as part of a DRMO Package and add a maintenance log entry for it
        for (EquipmentItem item : pkg.getIdentifiedItems()) {

            // Unassign item from current user
            try {
                equipmentItemService.unassignItem(item.getId());
            } catch (ServiceException e) {
                if (item.getAssignedUser() != null) {
                    log.warn("Unable to unassign item " + item.getSerial() + " from user " + item.getAssignedUser().getDisplayName());
                }
            }

            // Items are not set as part of a DRMO package until the package is closed
            item.setDrmoPackage(pkg);
            item.setItemStatus(Status.Drmo);
            log.trace("Marked item " + item.getSerial() + " as part of closed DRMO Package " + pkg.getDtid());

            // Create a maintenance entry for the turnin event
            MaintenanceEntry maint = new MaintenanceEntry();
            maint.setItem(item);
            maint.setEntryDate(new Date());
            maint.setEntryText("Item turned in to DRMO (package: " + pkg.getDtid() + ")");

            maintenanceEntryDao.save(maint);
            item.getMaintenanceEntries().add(maint);

            equipmentItemDao.save(item);

            drmoPackageDao.save(pkg);
        }
    }

    public List<DrmoPackage> getAllByAdpeAccount(AdpeAccount adpeAccount) {

        return drmoPackageDao.getAllByAdpeAccount(adpeAccount);
    }

    public List<DrmoPackage> getPendingByAdpeAccount(AdpeAccount adpeAccount) {

        return drmoPackageDao.getPendingByAdpeAccount(adpeAccount);

    }

    public int getPendingCountByAdpeAccount(AdpeAccount adpeAccount) {

        return drmoPackageDao.getPendingCountByAdpeAccount(adpeAccount);

    }

    public DrmoPackage createPackage(String dtid, AdpeAccount acct) {

        DrmoPackage pkg = new DrmoPackage();
        pkg.setDtid(dtid);
        pkg.setAdpeAccount(acct);

        drmoPackageDao.saveOrUpdate(pkg);

        return pkg;
    }

    public void addItem(String dtid, EquipmentItem item) {

        DrmoPackage pkg = drmoPackageDao.getByDtid(dtid);
        pkg.getIdentifiedItems().add(item);

    }

    public DrmoPackage getById(int id) {

        return drmoPackageDao.getById(id);
    }

    public List<DrmoPackage> getAll() {

        return drmoPackageDao.getAll();
    }
}
